/*
 * Powered By XY
 * Since 2020
 */

package com.xy.biz.ts.service.impl;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import com.xy.biz.mc.client.MessagePushClient;
import com.xy.biz.mc.domain.Message;
import com.xy.biz.mc.domain.consts.MessageTypeConstant;
import com.xy.biz.mc.domain.req.MessagePushRequest;
import com.xy.biz.ts.domain.bo.*;
import com.xy.biz.ts.domain.converter.ExaminationPaperConverter;
import com.xy.biz.ts.domain.converter.ExaminationTrainRelConverter;
import com.xy.biz.ts.domain.query.ExaminationRecordQuery;
import com.xy.biz.ts.domain.query.TrainUserQuery;
import com.xy.biz.ts.domain.req.SaveExaminationTrainRelRequest;
import com.xy.biz.ts.domain.resp.GetExaminationPaperResponse;
import com.xy.biz.ts.domain.resp.GetExaminationTrainRelResponse;
import com.xy.biz.ts.manager.*;
import com.xy.lang.domain.Page;
import com.xy.tool.context.UserContext;
import com.xy.tool.context.UserContextHolder;
import com.xy.tool.json.JsonUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.xy.lang.domain.Result;
import com.xy.biz.ts.domain.query.ExaminationTrainRelQuery;
import com.xy.biz.ts.service.ExaminationTrainRelService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

/**
 *
 *
 * @author zgy
 * @date 2021-7-8
 */
@Service
public class ExaminationTrainRelServiceImpl implements ExaminationTrainRelService, InitializingBean {

    @Autowired
    private ExaminationTrainRelManager examinationTrainRelManager;
    @Autowired
    private ExaminationPaperManager examinationPaperManager;
    @Autowired
    private ExaminationRecordManager examinationRecordManager;
    @Autowired
    private TrainUserManager trainUserManager;
    @Autowired
    private MessagePushClient messagePushClient;
    @Autowired
    private TrainManager trainManager;
    @Autowired
    private TrainEventBus trainEventBus;

    @Override
    @Transactional
    public Result<?> saveExaminationTrainRel(SaveExaminationTrainRelRequest request) {
        //改变原答题的状态
        trainEventBus.fireTrainExaminationHandler(request.getTrainId());
        //查询是否还有未完成的考核
        List<ExaminationTrainRelBO> examinationTrainRelBOS = examinationTrainRelManager.listExaminationTrainRel(ExaminationTrainRelQuery.max().trainId(request.getTrainId()).status(1).build());
        if (!CollectionUtils.isEmpty(examinationTrainRelBOS)) {
            return Result.fail("", "先前发起的考核还有人未开始答题！");
        }
        ExaminationTrainRelBO examinationTrainRelBO = ExaminationTrainRelConverter.toBO(request);
        buildRel(examinationTrainRelBO);
        int affectedRows = examinationTrainRelManager.saveExaminationTrainRel(examinationTrainRelBO);
        if (affectedRows > 0) {
            int i = trainManager.startExamination(request.getTrainId());
            //给参加考核人发送消息
            Set<Long> userIds = trainUserManager.listTrainUser(TrainUserQuery.max().trainId(request.getTrainId()).build()).stream().map(TrainUserBO::getUserId).collect(Collectors.toSet());
            //定义消息内容
            Message message = Message.builder()
                    .type(MessageTypeConstant.TYPE_FLOW)
                    .data(0)
                    .remark(request.getTrainName() + " 已开始考核，请尽快完成！")
                    .path(MessageTypeConstant.DOCUMENT_RELEASE_CHECK)
                    .build();
            userIds.forEach(u -> sendMessage(message, u));
            return Result.success(i);
        }
        return Result.ofErrorRowsAffected();
    }

    private void buildRel(ExaminationTrainRelBO examinationTrainRelBO) {
        LocalDateTime now = LocalDateTime.now();
        examinationTrainRelBO.setCreateTime(now);
        examinationTrainRelBO.setUpdateTime(now);
        examinationTrainRelBO.setStatus(1);
    }

    @Override
    public Result<?> saveAllExaminationTrainRel(Collection<ExaminationTrainRelBO> collection) {
        int affectedRows = examinationTrainRelManager.saveAllExaminationTrainRel(collection);
        if (affectedRows > 0) {
            return Result.success();
        }
        return Result.ofErrorRowsAffected();
    }

    @Override
    public Result<?> updateExaminationTrainRel(ExaminationTrainRelBO examinationTrainRelBO) {
        int affectedRows = examinationTrainRelManager.updateExaminationTrainRel(examinationTrainRelBO);
        if (affectedRows > 0) {
            return Result.success();
        }
        return Result.ofErrorRowsAffected();
    }

    @Override
    public Result<?> disableExaminationTrainRel(ExaminationTrainRelBO examinationTrainRelBO) {
        int affectedRows = examinationTrainRelManager.disableExaminationTrainRel(examinationTrainRelBO);
        if (affectedRows > 0) {
            return Result.success();
        }
        return Result.ofErrorRowsAffected();
    }

    @Override
    public Result<?> deleteExaminationTrainRel(Long examinationTrainRelId) {
        int affectedRows = examinationTrainRelManager.deleteExaminationTrainRel(examinationTrainRelId);
        if (affectedRows > 0) {
            return Result.success();
        }
        return Result.ofErrorRowsAffected();
    }

    @Override
    public ExaminationTrainRelBO getExaminationTrainRel(Long examinationTrainRelId) {
        return examinationTrainRelManager.getExaminationTrainRel(examinationTrainRelId);
    }

    @Override
    public List<ExaminationTrainRelBO> listExaminationTrainRelById(Collection<Long> collection) {
        return examinationTrainRelManager.listExaminationTrainRelById(collection);
    }

    @Override
    public List<GetExaminationPaperResponse> listExaminationTrainRel(ExaminationTrainRelQuery query) {
        Set<Long> collect = trainUserManager.listTrainUser(TrainUserQuery.max().userId(UserContextHolder.getUserId()).build()).stream().map(TrainUserBO::getTrainId).collect(Collectors.toSet());
        query.setTrainIds(collect);
        List<ExaminationTrainRelBO> examinationTrainRelBOS = examinationTrainRelManager.listExaminationTrainRel(query);
        //获取启用的集合
        Map<Long, ExaminationTrainRelBO> map = examinationTrainRelBOS.stream().filter(e -> e.getStatus() == 1).collect(Collectors.toMap(ExaminationTrainRelBO::getTrainId, e -> e));
        Set<Long> examinationIds = examinationTrainRelBOS.stream().filter(e -> e.getStatus() == 1).map(ExaminationTrainRelBO::getExaminationPaperId).collect(Collectors.toSet());
        Set<Long> trainIds = map.keySet();
        //根据启用试卷ID查试卷
        Map<Long, ExaminationPaperBO> examinationPaperBOMap = examinationPaperManager.listExaminationPaperById(examinationIds).stream().collect(Collectors.toMap(ExaminationPaperBO::getExaminationPaperId, e -> e));
        //查找启用的培训
        Map<Long, TrainBO> trainBOMap = trainManager.listTrainById(trainIds).stream().collect(Collectors.toMap(TrainBO::getTrainId, e -> e));
        List<ExaminationPaperBO> examinationPaperBOS = new ArrayList<>();
        //trainIds.forEach(t -> {
        for (Long t : trainIds) {
            ExaminationTrainRelBO examinationTrainRelBO = map.get(t);
            ExaminationPaperBO examinationPaperBO = new ExaminationPaperBO(examinationPaperBOMap.get(examinationTrainRelBO.getExaminationPaperId()));
            TrainBO trainBO = trainBOMap.get(t);
            examinationPaperBO.setTrainName(trainBO.getName());
            examinationPaperBO.setTrainId(trainBO.getTrainId());
            examinationPaperBOS.add(examinationPaperBO);
        }
        //});
        return ExaminationPaperConverter.toResponse(examinationPaperBOS);
    }

    @Override
    public int countExaminationTrainRel(ExaminationTrainRelQuery query) {
        query.setOffset(0);
        query.setRows(ExaminationTrainRelQuery.MAX_PAGE_SIZE);
        List<ExaminationTrainRelBO> examinationTrainRelBOS = examinationTrainRelManager.listExaminationTrainRel(query);
        Set<Long> examinationIds = examinationTrainRelBOS.stream().map(ExaminationTrainRelBO::getExaminationPaperId).collect(Collectors.toSet());
        List<ExaminationPaperBO> examinationPaperBOS = examinationPaperManager.listExaminationPaperById(examinationIds);
        return CollectionUtils.isEmpty(examinationTrainRelBOS) ? 0 : examinationPaperBOS.size();
    }


    @Override
    public void afterPropertiesSet() throws Exception {
        trainEventBus.addTrainExaminationHandler((trainId -> {
            //查找此培训发起的考核是否全部完成，完成后则将之前的考核设置为停用
            Set<Long> examinationRecordUserIds = examinationRecordManager.listExaminationRecord(ExaminationRecordQuery.max().trainId(trainId).build()).stream().map(ExaminationRecordBO::getExamineeUserId).collect(Collectors.toSet());
            //查询培训发行的人员
            Set<Long> releaseUserIds = trainUserManager.listTrainUser(TrainUserQuery.max().trainId(trainId).withPracticeRecords(false).withExaminationRecords(false).withLearnRecords(false).build()).stream().map(TrainUserBO::getUserId).collect(Collectors.toSet());
            Set<Long> reduce = releaseUserIds.stream().filter(item -> !examinationRecordUserIds.contains(item)).collect(Collectors.toSet());
            if (CollectionUtils.isEmpty(reduce)) {
                //若所有人都参加考核，则此培训考核关系设为停用
                examinationTrainRelManager.disableExaminationTrainRel(ExaminationTrainRelBO.builder().trainId(trainId).status(0).build());
            }
        }));
    }

    /**
     * 发送信息
     * @param message
     * @param toId
     */
    protected void sendMessage(Message message, Long toId) {
        messagePushClient.send(MessagePushRequest.builder()
                .data(JsonUtils.toJson(message).getBytes())
                .dataType(0)
                .expiredSeconds(0L)
                .toId(toId)
                .offlineFlag(true).build());
    }
}
